home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / tcpsubr.c < prev    next >
C/C++ Source or Header  |  1991-03-18  |  7KB  |  332 lines

  1. /* Low level TCP routines:
  2.  *  control block management
  3.  *  sequence number logical operations
  4.  *  state transitions
  5.  *  RTT cacheing
  6.  *  garbage collection
  7.  *
  8.  * Copyright 1991 Phil Karn, KA9Q
  9.  */
  10. #include <stdio.h>
  11. #include "global.h"
  12. #include "timer.h"
  13. #include "mbuf.h"
  14. #include "netuser.h"
  15. #include "internet.h"
  16. #include "tcp.h"
  17. #include "ip.h"
  18.  
  19. /* TCP connection states */
  20. char *Tcpstates[] = {
  21.     "",
  22.     "Closed",
  23.     "Listen",
  24.     "SYN sent",
  25.     "SYN received",
  26.     "Established",
  27.     "FIN wait 1",
  28.     "FIN wait 2",
  29.     "Close wait",
  30.     "Last ACK",
  31.     "Closing",
  32.     "Time wait"
  33. };
  34.  
  35. /* TCP closing reasons */
  36. char *Tcpreasons[] = {
  37.     "Normal",
  38.     "Reset/Refused",
  39.     "Timeout",
  40.     "ICMP"
  41. };
  42. struct tcb *Tcbs;        /* Head of control block list */
  43. int16 Tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  44. int32 Tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  45. int Tcp_trace;            /* State change tracing flag */
  46. int Tcp_syndata;
  47. struct tcp_rtt Tcp_rtt[RTTCACHE];
  48. struct mib_entry Tcp_mib[] = {
  49.     NULLCHAR,        0,
  50.     "tcpRtoAlgorithm",    4,    /* Van Jacobsen's algorithm */
  51.     "tcpRtoMin",        0,    /* No lower bound */
  52.     "tcpRtoMax",        MAXINT32,    /* No upper bound */
  53.     "tcpMaxConn",        -1L,    /* No limit */
  54.     "tcpActiveOpens",    0,
  55.     "tcpPassiveOpens",    0,
  56.     "tcpAttemptFails",    0,
  57.     "tcpEstabResets",    0,
  58.     "tcpCurrEstab",        0,
  59.     "tcpInSegs",        0,
  60.     "tcpOutSegs",        0,
  61.     "tcpRetransSegs",    0,
  62.     NULLCHAR,        0,    /* Connection state goes here */
  63.     "tcpInErrs",        0,
  64.     "tcpOutRsts",        0,
  65. };
  66.  
  67.  
  68. /* Look up TCP connection
  69.  * Return TCB pointer or NULLTCB if nonexistant.
  70.  * Also move the entry to the top of the list to speed future searches.
  71.  */
  72. struct tcb *
  73. lookup_tcb(conn)
  74. register struct connection *conn;
  75. {
  76.     register struct tcb *tcb;
  77.     struct tcb *tcblast = NULLTCB;
  78.  
  79.     for(tcb=Tcbs;tcb != NULLTCB;tcblast = tcb,tcb = tcb->next){
  80.         /* Yet another structure compatibility hack */
  81.         if(conn->remote.port == tcb->conn.remote.port
  82.          && conn->local.port == tcb->conn.local.port
  83.          && conn->remote.address == tcb->conn.remote.address
  84.          && conn->local.address == tcb->conn.local.address){
  85.             if(tcblast != NULLTCB){
  86.                 /* Move to top of list */
  87.                 tcblast->next = tcb->next;
  88.                 tcb->next = Tcbs;
  89.                 Tcbs = tcb;
  90.             }
  91.             return tcb;
  92.         }
  93.  
  94.     }
  95.     return NULLTCB;
  96. }
  97.  
  98. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  99. struct tcb *
  100. create_tcb(conn)
  101. struct connection *conn;
  102. {
  103.     register struct tcb *tcb;
  104.     struct tcp_rtt *tp;
  105.  
  106.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  107.         return tcb;
  108.     tcb = (struct tcb *)callocw(1,sizeof (struct tcb));
  109.     ASSIGN(tcb->conn,*conn);
  110.  
  111.     tcb->state = TCP_CLOSED;
  112.     tcb->cwind = tcb->mss = Tcp_mss;
  113.     tcb->ssthresh = 65535;
  114.     if((tp = rtt_get(tcb->conn.remote.address)) != NULLRTT){
  115.         tcb->srtt = tp->srtt;
  116.         tcb->mdev = tp->mdev;
  117.     } else {
  118.         tcb->srtt = Tcp_irtt;    /* mdev = 0 */
  119.     }
  120.     /* Initialize timer intervals */
  121.     set_timer(&tcb->timer,tcb->srtt);
  122.     tcb->timer.func = tcp_timeout;
  123.     tcb->timer.arg = tcb;
  124.  
  125.     tcb->next = Tcbs;
  126.     Tcbs = tcb;        
  127.     return tcb;
  128. }
  129.  
  130. /* Close our TCB */
  131. void
  132. close_self(tcb,reason)
  133. register struct tcb *tcb;
  134. int reason;
  135. {
  136.     struct reseq *rp1;
  137.     register struct reseq *rp;
  138.  
  139.     if(tcb == NULLTCB)
  140.         return;
  141.  
  142.     stop_timer(&tcb->timer);
  143.     tcb->reason = reason;
  144.  
  145.     /* Flush reassembly queue; nothing more can arrive */
  146.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  147.         rp1 = rp->next;
  148.         free_p(rp->bp);
  149.         free((char *)rp);
  150.     }
  151.     tcb->reseq = NULLRESEQ;
  152.     setstate(tcb,TCP_CLOSED);
  153. }
  154.  
  155. /* Sequence number comparisons
  156.  * Return true if x is between low and high inclusive,
  157.  * false otherwise
  158.  */
  159. int
  160. seq_within(x,low,high)
  161. register int32 x,low,high;
  162. {
  163.     if(low <= high){
  164.         if(low <= x && x <= high)
  165.             return 1;
  166.     } else {
  167.         if(low >= x && x >= high)
  168.             return 1;
  169.     }
  170.     return 0;
  171. }
  172. int
  173. seq_lt(x,y)
  174. register int32 x,y;
  175. {
  176.     return (long)(x-y) < 0;
  177. }
  178. #ifdef    notdef
  179. int
  180. seq_le(x,y)
  181. register int32 x,y;
  182. {
  183.     return (long)(x-y) <= 0;
  184. }
  185. #endif    /* notdef */
  186. int
  187. seq_gt(x,y)
  188. register int32 x,y;
  189. {
  190.     return (long)(x-y) > 0;
  191. }
  192. int
  193. seq_ge(x,y)
  194. register int32 x,y;
  195. {
  196.     return (long)(x-y) >= 0;
  197. }
  198.  
  199. void
  200. setstate(tcb,newstate)
  201. register struct tcb *tcb;
  202. register int newstate;
  203. {
  204.     register char oldstate;
  205.  
  206.     oldstate = tcb->state;
  207.     tcb->state = newstate;
  208.     if(Tcp_trace)
  209.         printf("TCB %lx %s -> %s\n",ptol(tcb),
  210.          Tcpstates[oldstate],Tcpstates[newstate]);
  211.  
  212.     /* Update MIB variables */
  213.     switch(oldstate){
  214.     case TCP_CLOSED:
  215.         if(newstate == TCP_SYN_SENT)
  216.             tcpActiveOpens++;
  217.         break;
  218.     case TCP_LISTEN:
  219.         if(newstate == TCP_SYN_RECEIVED)
  220.             tcpPassiveOpens++;
  221.         break;
  222.     case TCP_SYN_SENT:
  223.         if(newstate == TCP_CLOSED)
  224.             tcpAttemptFails++; 
  225.         break;
  226.     case TCP_SYN_RECEIVED:
  227.         switch(newstate){
  228.         case TCP_CLOSED:
  229.         case TCP_LISTEN:
  230.             tcpAttemptFails++; 
  231.             break;
  232.         }
  233.         break;
  234.     case TCP_ESTABLISHED:
  235.     case TCP_CLOSE_WAIT:
  236.         switch(newstate){
  237.         case TCP_CLOSED:
  238.         case TCP_LISTEN:
  239.             tcpEstabResets++;
  240.             break;
  241.         }
  242.         tcpCurrEstab--;
  243.         break;
  244.     }
  245.     if(newstate == TCP_ESTABLISHED || newstate == TCP_CLOSE_WAIT)
  246.         tcpCurrEstab++;
  247.  
  248.     if(tcb->s_upcall)
  249.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  250.  
  251.     switch(newstate){
  252.     case TCP_SYN_RECEIVED:    /***/
  253.     case TCP_ESTABLISHED:
  254.         /* Notify the user that he can begin sending data */
  255.         if(tcb->t_upcall)
  256.             (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  257.         break;
  258.     }
  259. }
  260. /* Round trip timing cache routines.
  261.  * These functions implement a very simple system for keeping track of
  262.  * network performance for future use in new connections.
  263.  * The emphasis here is on speed of update (rather than optimum cache hit
  264.  * ratio) since rtt_add is called every time a TCP connection updates
  265.  * its round trip estimate.
  266.  */
  267. void
  268. rtt_add(addr,rtt)
  269. int32 addr;        /* Destination IP address */
  270. int32 rtt;
  271. {
  272.     register struct tcp_rtt *tp;
  273.     int32 abserr;
  274.  
  275.     if(addr == 0)
  276.         return;
  277.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  278.     if(tp->addr != addr){
  279.         /* New entry */
  280.         tp->addr = addr;
  281.         tp->srtt = rtt;
  282.         tp->mdev = 0;
  283.     } else {
  284.         /* Run our own SRTT and MDEV integrators, with rounding */
  285.         abserr = (rtt > tp->srtt) ? rtt - tp->srtt : tp->srtt - rtt;
  286.         tp->srtt = ((AGAIN-1)*tp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  287.         tp->mdev = ((DGAIN-1)*tp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  288.     }
  289. }
  290. struct tcp_rtt *
  291. rtt_get(addr)
  292. int32 addr;
  293. {
  294.     register struct tcp_rtt *tp;
  295.  
  296.     if(addr == 0)
  297.         return NULLRTT;
  298.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  299.     if(tp->addr != addr)
  300.         return NULLRTT;
  301.     return tp;
  302. }
  303.  
  304. /* TCP garbage collection - called by storage allocator when free space
  305.  * runs low. The send and receive queues are crunched. If the situation
  306.  * is red, the resequencing queue is discarded; otherwise it is
  307.  * also crunched.
  308.  */
  309. void
  310. tcp_garbage(red)
  311. int red;
  312. {
  313.     register struct tcb *tcb;
  314.     struct reseq *rp,*rp1;
  315.  
  316.     for(tcb = Tcbs;tcb != NULLTCB;tcb = tcb->next){
  317.         mbuf_crunch(&tcb->rcvq);
  318.         mbuf_crunch(&tcb->sndq);
  319.         for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  320.             rp1 = rp->next;
  321.             if(red){
  322.                 free_p(rp->bp);
  323.                 free((char *)rp);
  324.             } else {
  325.                 mbuf_crunch(&rp->bp);
  326.             }
  327.         }
  328.         if(red)
  329.             tcb->reseq = NULLRESEQ;
  330.     }
  331. }
  332.